package jsonmarshal

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

//ErrInvalidType ...
var ErrInvalidType = errors.New("Invalid type")

// StringToJson 将string 类型转成 JSON 编码
func StringToJson(s string) string {
	r := []rune(s)
	str1 := "\\u003c"
	str2 := "\\u003e"
	str3 := "\\u0026"

	res := ""

	for _, a := range r {
		if rune(a) == rune('<') {
			res = res + str1
		} else if rune(a) == rune('>') {
			res = res + str2
		} else if rune(a) == rune('&') {
			res = res + str3
		} else {
			res = res + string(a)
		}
	}
	return string(res)
}

//HandleTag 分类处理 tag 值
func HandleTag(tag reflect.StructTag) int {
	field, ok := tag.Lookup("json")
	if !ok {
		//跳过，不用处理该字段
		return 0
	}
	if field == "-" {
		//忽略该字段
		return 1
	}
	if field == "-," {
		//该字段的键为"-"
		return 2
	}
	sep := ","
	arr := strings.Split(field, sep)

	if len(arr) != 2 {
		//该字段的键为field
		return 5
	}

	if arr[1] == "omitempty" {
		if arr[0] == "" {
			//该字段的键为field，如果值为空，省略该字段
			return 3
		} else {
			//该字段的键为arr[0]，如果值为空，省略该字段
			return 4
		}
	} else {
		//该标签无效，跳过
		return 0
	}
}

// DataToJson 将接口 v 转换为 JSON 编码的字符串。
func DataToJson(v interface{}) string {
	res := ""
	vtype := reflect.TypeOf(v)
	vvalue := reflect.ValueOf(v)

	typee := vtype.Kind()

	switch typee {
	case reflect.Ptr, reflect.Uintptr:
		return DataToJson(vvalue.Elem().Interface())

	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
		reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
		reflect.Uint64, reflect.Float32, reflect.Float64:
		res = fmt.Sprintf("%v", v)

	case reflect.String:
		var vstr = fmt.Sprintf("%v", v)
		res = StringToJson(vstr)
		res = "\"" + res + "\""

	case reflect.Slice:
		for i := 0; i < vvalue.Len(); i++ {
			res += DataToJson(vvalue.Index(i).Interface())
			res += ","
		}
		//删掉最右边的 "," 号
		return "[" + strings.TrimRight(res, ",") + "]"

	case reflect.Map:
		keys := vvalue.MapKeys()
		for i := 0; i < len(keys); i++ {
			key := keys[i]
			value := vvalue.MapIndex(key)
			res += DataToJson(key.Interface()) + ":" + DataToJson(value.Interface())
			res += ","
		}
		//删除最右边的 "," 号
		return "{" + strings.TrimRight(res, ",") + "}"

	case reflect.Struct:
		result := ""
		for i := 0; i < vtype.NumField(); i++ {
			field := vtype.Field(i)
			value := vvalue.Field(i)
			if field.PkgPath == "" {
				//处理tag标签
				tag := field.Tag
				json := tag.Get("json")
				sep := ","
				arr1 := strings.Split(json, sep)
				key := field.Name

				num := HandleTag(tag)
				if num == 1 {
					continue
				}
				if num == 2 {
					key = "-"
				}
				if num == 5 {
					key = json
				}
				if num == 3 {
					//判断值是否为空
					if value.Interface() == 0 || value.Interface() == "" || value.Interface() == 0.0 {
						continue
					}
				}

				if num == 4 {
					//判断值是否为空
					if value.Interface() == 0 || value.Interface() == "" || value.Interface() == 0.0 {
						continue
					}
					key = arr1[0]
				}

				key = "\"" + key + "\""
				result += key + ":" + DataToJson(value.Interface()) + ","
			}
		}
		// 删掉最右边的 "," 号
		return "{" + strings.TrimRight(result, ",") + "}"
	}

	return res
}

//JsonMarshal 通过调用 DataToJson 函数将接口 v 的具体值转换为 JSON 编码规格的字符串，然后通过强制类型转换将字符串转换成 []byte
//类型并返回。期间如果出现不能转换为 JSON 编码的值时将返回自定义的 ErrInvalidType 错误。
func JsonMarshal(v interface{}) ([]byte, error) {
	result := DataToJson(v)
	if result == "" {
		return nil, ErrInvalidType
	}
	return []byte(result), nil
}
